﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace Core
{
    public class Graph
    {

        public enum TypeOfGraph
        {
            [Description("Клиентский порт")]
            Process,
            [Description("Серверный порт")]
            Chenal
        }

        #region Поля
        public String Name { get; set; }
        public List<Node> Struct { get; private set; }
        public Node SelectedNode { get; set; }
        public Link SelectedLink { get; set; }
        public bool IsStartNode { get; set; }
        public Node StartNode { get; private set; }
        public bool IsNodeSelected { get; private set; }
        public bool IsActiveNow { get; private set; }
        public TypeOfGraph TypeOf { get; private set; }
        #endregion
        
       

        public Graph()
        {
            IsActiveNow = true;
            Struct = new List<Node>();
            SelectedNode = null;
            IsStartNode = false;
        }      

        public void MakeActive()
        {
            IsActiveNow = true;
        }

        public void MakePassive()
        {
            IsActiveNow = false;
        }

        public void MakeItChenal()
        {
            TypeOf = TypeOfGraph.Chenal;
        }

        public void MackeItProc()
        {
            TypeOf = TypeOfGraph.Process;
        }

        public Node SelectNode(int xc, int yc)
        {
            IsNodeSelected = false;
            if (SelectedNode != null)
                SelectedNode.UnSelect();
            Node result = null;
            var ar =Struct.Where(x => (Math.Sqrt((xc - x.X) * (xc - x.X) + (yc - x.Y) * (yc - x.Y))) < 15).ToArray();
            if (ar.Length > 0)
            {
                result = ar[0];
                result.Select();
            }
            SelectedNode = result;
            if (result != null)
                IsNodeSelected = true;
            return result;
        }

        public bool SelectLink(int xm, int ym)
        {
            
            foreach (Node node in Struct)
            {
                var ar = node.Linking.Where(y => (xm > y.X - 10) && (xm < y.X + 10) && (ym > y.Y - 10) && (ym < y.Y + 10)).ToArray();
                if(ar.Length >0)
                {
                    SelectedLink = ar[0];
                    return true;
                }
            }
            return false;
           
        }
        
        private int GetLabel()
        {
            for (int i = 0; i < Struct.Count + 1; i++)
            {
                if (Struct.Where(item => item.Number == i + 1).ToArray().Length == 0)
                    return  i + 1;
            }
            return 0;
        }

        private bool IsNormalize()
        {
            return Struct.All(node => (node.X != 0) && (node.Y != 0));
        }

        public void TryNormalize(int widh, int hight)
        {
            if(!IsNormalize())
            {
                int xc = widh/2;
                int yc = hight/2;
                int r = (int) (Math.Min(widh/2, hight/2)*0.5);
                var a = 2*Math.PI/Struct.Count;
                int i = 0;
                foreach (Node node in Struct)
                {
                    node.X = (int) (xc + r*Math.Cos(a*i));
                    node.Y = (int)(yc + r * Math.Sin(a * i ));
                    i++;
                }
                foreach (Link link in Struct.SelectMany(node => node.Linking))
                {
                    link.Replace();
                }
                
            }
        }

        public Node AddNode(int x, int y, String name, byte nodtype)
        {
            
            Node temp = new Node(x, y, name, (TypeOfNode) nodtype,TypeOf);
            if(name == "")
            {
                temp.Number = GetLabel();
                temp.Id = 'L' + temp.Number.ToString();
            }
            if (nodtype == 3)
            {
                IsStartNode = true;
                StartNode = temp;
            }
            Struct.Add(temp);
            SelectedNode = temp;
            return temp;
        }

        public void DeleteLink()
        {
            Struct.Where(x => x.Linking.Where(y => y == SelectedLink).ToArray().Length > 0).ToArray()[0].DeleteLink(SelectedLink);
            
        }

        public void DeleteNode()
        {
            foreach (Node node in Struct)
            {
                node.Linking.RemoveAll(x => x._next == SelectedNode);
            }
            Struct.Remove(SelectedNode);
            if(SelectedNode == StartNode)
            {
                IsStartNode = false;
                StartNode = null;
            }
            SelectedNode = null;
        }

        public void SetStartNode(Node node)
        {
            StartNode = node;
            IsStartNode = true;
        }

        public override string ToString()
        {
            String result = "";
            String temp = "";
            switch (TypeOf)
            {
                case TypeOfGraph.Process:
                    {
                        temp = "process";
                        break;
                    }
                case TypeOfGraph.Chenal:
                    {
                        temp = "channel";
                        break;
                    }
            }
            string start = "";
            if (IsStartNode)
                start = StartNode.Id;
            result += '<' + temp + " id=" + '"' + Name + '"' + " entery=" + '"' + start  + '"' + " templet=" +
                      '"' + '"' + " rem=" + '"' + '"' + '>' + "\r\n";
            result = Struct.Aggregate(result, (current, node) => current + node.ToString());
            result += "</" + temp + '>' + "\r\n";
            return result;
        }
    }
}
